﻿using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;

namespace ShinePipe
{
    /// <summary>
    /// U3D支持全双工存在未知问题，故而此处实现为开两个管道，一个负责写一个负责读
    /// </summary>
    public class ShineNamePipeServer
    {
        /// <summary>
        /// 接收事件
        /// </summary>
        public event ShinePipeRecvEventHandler ShinePipeRecvEvent;

        /// <summary>
        /// 关闭事件
        /// </summary>
        public event ShinePipeCloseEventHandler ShinePipeCloseEvent;

        /// <summary>
        /// 测试用
        /// </summary>
        public event ShinePipeDebugEventHandler ShinePipeDebugEvent;

        /// <summary>
        /// 服务器管道
        /// </summary>
        private NamedPipeServerStream _pipeServer;

        /// <summary>
        /// 启动命名管道
        /// </summary>
        /// <param name="p_pipeName"></param>
        public void Start(string p_pipeName)
        {
            try
            {
                _pipeServer = new NamedPipeServerStream(p_pipeName, PipeDirection.InOut, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 创建成功" });
                }
                WaitConnect();
            }
            catch (ExecutionEngineException e)
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 创建失败" });
                }

                throw;
            }
        }

        /// <summary>
        /// 停止命名管道
        /// </summary>
        public void Stop()
        {
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 申请关闭" });
            }
            if (_pipeServer.IsConnected)
            {
                Write(@"NamePipeCloseReq");
            }
            else
            {
                Dispose();
            }
        }

        /// <summary>
        /// 停止线程
        /// </summary>
        private void Dispose()
        {
            _pipeServer.Close();
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 关闭" });
            }

            _pipeServer.Dispose();
            _pipeServer = null;
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 释放" });
            }
            GC.Collect();

            if (ShinePipeCloseEvent != null)
            {
                ShinePipeCloseEvent(this, new ShinePipeCloseEventArgs() { Message = @"" });
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="p_msg"></param>
        public void Write(string p_msg)
        {
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 准备发送：" + p_msg });
            }

            if (_pipeServer != null && _pipeServer.IsConnected)
            {

                byte[] bytesArray = System.Text.Encoding.Unicode.GetBytes(p_msg);
                _pipeServer.BeginWrite(bytesArray
                    , 0
                    , bytesArray.Length
                    , ar =>
                        {
                            if (ar.IsCompleted)
                            {
                                try
                                {
                                    _pipeServer.EndWrite(ar);
                                    string msg = ar.AsyncState.ToString();
                                    if (ShinePipeDebugEvent != null)
                                    {
                                        ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 成功 发送：" + msg });
                                    }
                                }
                                catch
                                {
                                    //管道关闭时会导致异步结束出错
                                }
                            }
                        }
                    , p_msg);
            }
            else
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 发送 失败，管道不存在或已经关闭" });
                }
            }
        }

        /// <summary>
        /// 等待连接
        /// </summary>
        private void WaitConnect()
        {
            if (ShinePipeDebugEvent != null)
            {
                ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 等待连接。。。" });
            }

            _pipeServer.BeginWaitForConnection
                (
                    ar => 
                        {
                            if (ar.IsCompleted)
                            {
                                try
                                {
                                    NamedPipeServerStream mServer = ar.AsyncState as NamedPipeServerStream;
                                    mServer.EndWaitForConnection(ar);
                                    if (ShinePipeDebugEvent != null)
                                    {
                                        ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 接收连接" });
                                    }
                                    ReadWork();
                                }
                                catch
                                {
                                    //不处理，在未接收到连接时，强行关闭管道，此处会抛错
                                }
                            }
                        }
                    , _pipeServer);
        }

        /// <summary>
        /// 读线程主函数
        /// </summary>
        private void ReadWork()
        {
            if (_pipeServer.IsConnected)
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 准备接收。。。" });
                }

                byte[] byteArray = new byte[2048];
                _pipeServer.BeginRead
                    (
                        byteArray
                        , 0
                        , byteArray.Length
                        , ar =>
                            {
                                if (ar.IsCompleted)
                                {
                                    try
                                    {
                                        _pipeServer.EndRead(ar);
                                        byte[] content = ar.AsyncState as byte[];
                                        string strTwmp = System.Text.Encoding.Unicode.GetString(content).Replace('\0', ' ').Trim();

                                        if (ShinePipeDebugEvent != null)
                                        {
                                            ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 成功 接收 " + strTwmp });
                                        }

                                        if (strTwmp == @"NamePipeCloseRes")
                                        {
                                            Dispose();
                                            return;
                                        }
                                        if (strTwmp == @"NamePipeCloseReq")
                                        {
                                            Write(@"NamePipeCloseRes");
                                            Thread.Sleep(100);
                                            Dispose();
                                            return;
                                        }

                                        if (ShinePipeRecvEvent != null)
                                        {
                                            ShinePipeRecvEvent(this, new ShinePipeRecvEventArgs() { Message = strTwmp });
                                        }


                                        ReadWork();//继续异步接收
                                    }
                                    catch
                                    {
                                        //管道关闭时会导致异步结束出错
                                    }
                                }
 
                            }
                        , byteArray);
            }
            else
            {
                if (ShinePipeDebugEvent != null)
                {
                    ShinePipeDebugEvent(this, new ShinePipeDebugEventArgs() { Message = @"服务器管道 接收 失败，管道不存在或已关闭" });
                }
            }
        }

    }
}
